const resolveChangeType = ({
  prevIsCollapsed,
  prevHasFocus,
  prevSelection,
  isCollapsed,
  hasFocus,
  selection
}) => {
  if (typeof prevIsCollapsed === "undefined") {
    return "init-change";
  }

  if (isCollapsed !== prevIsCollapsed) {
    return "collapsed-change";
  }

  if (hasFocus !== prevHasFocus) {
    return "focus-change";
  }

  if (isCollapsed) {
    const prevStartKey = prevSelection.getStartKey();
    const startKey = selection.getStartKey();

    if (prevStartKey === startKey) return "selection-move-inner-block";
    return "selection-move-outer-block";
  }
  const prevEndKey = prevSelection.getEndKey();
  const prevStartOffset = prevSelection.getStartOffset();
  const prevEndOffset = prevSelection.getEndOffset();
  const endKey = selection.getEndKey();
  const startOffset = selection.getStartOffset();
  const endOffset = selection.getEndOffset();

  if (
    prevEndKey === endKey &&
    prevStartOffset === startOffset &&
    prevEndOffset === endOffset
  ) {
    return "selection-range-content-change";
  }

  return "selection-range-size-change";
};

function SelectionChangePlugin() {
  let prevIsCollapsed;
  let prevSelection;
  let prevHasFocus;

  this.apply = getEditor => {
    const { hooks } = getEditor();

    hooks.syncSelectionChange.tap("SelectionChangePlugin", editorState => {
      const selection = editorState.getSelection();
      const isCollapsed = selection.isCollapsed();
      const hasFocus = selection.getHasFocus();

      const changeType = resolveChangeType({
        prevIsCollapsed,
        prevHasFocus,
        prevSelection,
        isCollapsed,
        hasFocus,
        selection
      });

      const payload = {
        changeType,
        oldValue: { prevIsCollapsed, prevHasFocus, prevSelection },
        newValue: { isCollapsed, hasFocus, selection }
      };

      prevIsCollapsed = isCollapsed;
      prevHasFocus = hasFocus;
      prevSelection = selection;

      switch (changeType) {
        case "init-change":
          hooks.selectionInitChange.call(editorState, payload);
          break;
        case "collapsed-change":
          hooks.selectionCollapsedChange.call(editorState, payload);
          break;
        case "focus-change":
          hooks.selectionFocusChange.call(editorState, payload);
          break;
        case "selection-move-inner-block":
          hooks.selectionMoveInnerBlock.call(editorState, payload);
          break;
        case "selection-move-outer-block":
          hooks.selectionMoveOuterBlock.call(editorState, payload);
          break;
        case "selection-range-content-change":
          hooks.selectionRangeContentChange.call(editorState, payload);
          hooks.selectionRangeChange.call(editorState, payload);
          break;
        case "selection-range-size-change":
          hooks.selectionRangeSizeChange.call(editorState, payload);
          hooks.selectionRangeChange.call(editorState, payload);
          break;
        default:
        // do nothing
      }
    });
  };
}

export default SelectionChangePlugin;
